package kr.ac.konkuk.dblab.point.builder;

import java.awt.geom.Point2D;
import java.util.Map;
import java.util.Set;

import kr.ac.konkuk.dblab.point.metadata.Quad;
import kr.ac.konkuk.dblab.point.metadata.Rect;
import kr.ac.konkuk.dblab.point.quadtree.Cell;
import kr.ac.konkuk.dblab.point.quadtree.CompositeNode;
import kr.ac.konkuk.dblab.point.quadtree.CompoundCell;
import kr.ac.konkuk.dblab.point.quadtree.Node;
import kr.ac.konkuk.dblab.point.quadtree.NodeType;
import kr.ac.konkuk.dblab.point.quadtree.Root;
import kr.ac.konkuk.dblab.point.utils.PointUtils;

public class QuadTreeBuilder {
	public static Root build(Set<Point2D> points, double unit) {
		Root root = createRoot(points);
		if (root.rect().width() > unit || root.rect().height() > unit) {
			build(root, points, unit);
		}
		return root;
	}
	
	private static void build(CompositeNode parent, Set<Point2D> points, double unit) {
		Map<NodeType, Quad<Point2D>> quads = PointUtils.makeQuad(points, parent.center(), parent.rect());
		for (NodeType type : quads.keySet()) {
			Quad<Point2D> quad = quads.get(type);
			Set<Point2D> ps = quad.getPoints();
			Rect rect = quad.getRect();
			Point2D center = new Point2D.Double((rect.left + rect.right)/2, (rect.top + rect.bottom)/2);
			
			if (rect.width() <= unit && rect.height() <= unit) {
				parent.attach(createCell(type, ps, rect, center));
			} else {
				CompositeNode cc = createCompoundCell(type, ps, rect, center);
				parent.attach(cc);
				build(cc, ps, unit);
			}
		}
	}
	
	private static Root createRoot(Set<Point2D> points) {
		Point2D center = new Point2D.Double();
		Rect rect = PointUtils.makeRectFromPoints(points, center);
		Root root = new Root();
		root.center(center);
		root.rect(rect);
		
		return root;
	}
	
	private static Node createCell(NodeType type, Set<Point2D> points, Rect rect, Point2D center) {
		Cell cell = new Cell(type);
		cell.points(points);
		cell.rect(rect);
		cell.center(center);
		
		return cell;
	}
	
	private static CompositeNode createCompoundCell(NodeType type, Set<Point2D> points, Rect rect, Point2D center) {
		CompoundCell cc = new CompoundCell(type);
		cc.center(center);
		cc.rect(rect);
		return cc;
	}
	
}
